#include "TimingWheel.h"
#include<iostream>
using namespace tmms::network;

TimingWheel::TimingWheel() : wheels_(4) 
{
    wheels_[KTimingTypeSecond].resize(60);
    wheels_[KTimingTypeMinute].resize(60);
    wheels_[KTimingTypeHour].resize(24);
    wheels_[KTimingTypeDay].resize(30);
}

TimingWheel::~TimingWheel()
{

}

void TimingWheel::InserEntry(uint32_t delay,EntryPtr entryPtr)
{
    if(delay<0){
         entryPtr.reset();
    }
    if(delay<KTimingMinute)
    {
        InserSecondEntry(delay,entryPtr);
    }else if(delay < KTimingHour){
        InserMinuteEntry(delay,entryPtr);
    }else if(delay < KTimingDay){
        InserHourEntry(delay,entryPtr);
    }else{
        auto day  =delay /KTimingDay;
        if(day>30){
            std::cout<<"天数大于30，报错了"<<std::endl;
            return ;
        }
        InserDayEntry(delay,entryPtr);
    }
}

void TimingWheel::InserSecondEntry(uint32_t delay,EntryPtr entryptr)
{
    wheels_[KTimingTypeSecond][delay-1].emplace(entryptr);//在那个callback元素的集合中插入好吧
}

void TimingWheel::InserMinuteEntry(uint32_t delay,EntryPtr entryPtr)
{
    auto minute = delay/KTimingMinute;
    auto second = delay %KTimingMinute;
    CallbackEntryPtr newEntryPtr = std::make_shared<CallbackEntry>([this,second,entryPtr](){
        InserEntry(second,entryPtr); //这个是CallbackEntry的构造函数的参数，也就是当这个（分钟轮）到达指定位置（如2分钟）时触发CallbackEntry析构 → 执行此Lambda，将原始任务重新插入秒级时间轮，而不是一开始就插入
    });
    wheels_[KTimingTypeMinute][minute-1].emplace(newEntryPtr);//在那个集合中插入好吧
}

void TimingWheel::InserHourEntry(uint32_t delay,EntryPtr entryPtr)
{
    auto hour = delay/KTimingHour;
    auto second = delay %KTimingHour;
    CallbackEntryPtr newEntryPtr = std::make_shared<CallbackEntry>([this,second,entryPtr](){
        InserEntry(second,entryPtr);
    });
    wheels_[KTimingTypeHour][hour-1].emplace(newEntryPtr);//在那个集合中插入好吧
}//std::shared_ptr<void>可以安全地持有任何类型的shared_ptr

void TimingWheel::InserDayEntry(uint32_t delay,EntryPtr entryPtr)
{
    auto day = delay/KTimingDay;
    auto second = delay %KTimingDay;
    CallbackEntryPtr newEntryPtr = std::make_shared<CallbackEntry>([this,second,entryPtr](){
        InserEntry(second,entryPtr);
    });
    wheels_[KTimingTypeDay][day-1].emplace(newEntryPtr);//在那个集合中插入好吧
}



void TimingWheel::OnTimer(int64_t now) //转动时间轮 要不断地传入now啊
{
    if(last_ts_ == 0)
    {
        last_ts_ = 0;
    }if(now - last_ts_ < 1000)
    {
        return ;
    }
    last_ts_ = now;
    ++tick_;

    PopUp(wheels_[KTimingTypeSecond]);
    if(tick_% KTimingMinute == 0)
    {
        PopUp(wheels_[KTimingMinute]); 
    }
    else  if(tick_% KTimingHour == 0)
    {
        PopUp(wheels_[KTimingHour]); 
    }else if(tick_% KTimingDay == 0)
    {
         PopUp(wheels_[KTimingDay]); 
    } 
}

void TimingWheel::PopUp(Wheel &bq)
{
    bq.front().clear(); //调用队头的set的clear(),
    bq.pop_front();//移除bq的第一个元素​​。此操作会删除队列头部元素，并将队列大小减1
    bq.push_back(WheelEntry());//再在队头插入一个空的集合，一个输入一个空的
}
void TimingWheel::RunAfter(double delay,const Func &cb)
{
    CallbackEntryPtr cbEntry = std::make_shared<CallbackEntry> ([cb](){
        cb();
    });
    InserEntry(delay,cbEntry);
} // 这样到期就会调用我们的回调函数

void TimingWheel::RunAfter(double delay,Func &&cb)
{

    CallbackEntryPtr cbEntry = std::make_shared<CallbackEntry> ([cb](){
        cb();
    });
    InserEntry(delay,cbEntry);
}

void TimingWheel::RunEvery(double interval,const Func &cb )
{ //每次触发之后就还会触发几次，间隔多少秒
    CallbackEntryPtr cbEntry = std::make_shared<CallbackEntry> ([this,cb,interval](){
        cb();
        RunEvery(interval,cb);//执行之后，又继续插入
    });
    InserEntry(interval,cbEntry);
}

void TimingWheel::RunEvery(double interval,Func &&cb )
{
    CallbackEntryPtr cbEntry = std::make_shared<CallbackEntry> ([this,cb,interval](){
        cb();
        RunEvery(interval,cb);
    });
    InserEntry(interval,cbEntry);
}
